package com.gooluke.mds.datasource;

import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author gooluke
 * description
 * datetime 2025-06-11 19:29
 */
public class MultiDataSourceContext {

    private static final Logger log = LoggerFactory.getLogger(MultiDataSourceContext.class);

    private static final ThreadLocal<MultiDataSourceInfo> MULTI_DATA_SOURCE_INFO_THREAD_LOCAL = new ThreadLocal<>();

    public static boolean enabled() {
        return MULTI_DATA_SOURCE_INFO_THREAD_LOCAL.get() != null;
    }

    public static void start(PlatformTransactionManager transactionManager, String[] datasourceNames, int propagation, int isolationLevel) {
        MultiDataSourceInfo multiDataSourceInfo = new MultiDataSourceInfo();
        multiDataSourceInfo.setTransactionManager(transactionManager);
        multiDataSourceInfo.setDataSourceNames(Arrays.asList(datasourceNames));
        multiDataSourceInfo.setPropagation(propagation);
        multiDataSourceInfo.setIsolationLevel(isolationLevel);
        multiDataSourceInfo.setTransactionDataList(new ArrayList<>());
        MULTI_DATA_SOURCE_INFO_THREAD_LOCAL.set(multiDataSourceInfo);
    }

    public static void checkTransaction(String dataSourceName) {
        // 切换数据源
        DatasourceContextHolder.setDatasource(dataSourceName);
        MultiDataSourceInfo multiDataSourceInfo = getMultiDataSourceInfo();
        PlatformTransactionManager transactionManager = multiDataSourceInfo.getTransactionManager();
        // 创建事务定义
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(multiDataSourceInfo.getPropagation());//传播属性
        def.setIsolationLevel(multiDataSourceInfo.getIsolationLevel());//隔离级别
        TransactionStatus status = transactionManager.getTransaction(def);
        TransactionData transactionData = new TransactionData(dataSourceName, status);
        multiDataSourceInfo.getTransactionDataList().add(transactionData);
    }

    public static MultiDataSourceInfo getMultiDataSourceInfo() {
        return MULTI_DATA_SOURCE_INFO_THREAD_LOCAL.get();
    }

    public static List<String> getDataSourceNames() {
        return getMultiDataSourceInfo().getDataSourceNames();
    }

    public static void commit() {
        MultiDataSourceInfo multiDataSourceInfo = getMultiDataSourceInfo();
        List<TransactionData> transactionDataList = multiDataSourceInfo.getTransactionDataList();
        PlatformTransactionManager transactionManager = multiDataSourceInfo.getTransactionManager();
        // 逆序提交事务
        for (int i = transactionDataList.size() - 1; i >= 0; i--) {
            TransactionData transactionData = transactionDataList.get(i);
            DatasourceContextHolder.setDatasource(transactionData.getDataSourceName());
            TransactionStatus status = transactionData.getTransactionStatus();
            if (!status.isCompleted()) {
                transactionManager.commit(status);
            }
        }
    }

    public static void rollback() {
        MultiDataSourceInfo multiDataSourceInfo = getMultiDataSourceInfo();
        List<TransactionData> transactionDataList = multiDataSourceInfo.getTransactionDataList();
        PlatformTransactionManager transactionManager = multiDataSourceInfo.getTransactionManager();
        // 逆序回滚事务
        for (int i = transactionDataList.size() - 1; i >= 0; i--) {
            TransactionData transactionData = transactionDataList.get(i);
            DatasourceContextHolder.setDatasource(transactionData.getDataSourceName());
            TransactionStatus status = transactionData.getTransactionStatus();
            if (!status.isCompleted()) {
                transactionManager.rollback(status);
            }
        }
    }

    public static void clear() {
        MULTI_DATA_SOURCE_INFO_THREAD_LOCAL.remove();
    }

    @Data
    public static class MultiDataSourceInfo {
        private PlatformTransactionManager transactionManager;
        private int propagation;
        private int isolationLevel;
        private List<String> dataSourceNames;
        //private Map<String, TransactionStatus> transactionStatusMap;
        private List<TransactionData> transactionDataList;
    }

}
